home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Megahits 5
/
Megahits 5 (1994)(GTI - Rhein-Main-Soft)(DE)(Disc 2 of 2)[!].iso
/
archive
/
conv
/
buildmpeg.lha
/
BuildMPEG.ifx
next >
Wrap
Text File
|
1994-03-22
|
16KB
|
628 lines
/*
* BuildMPEG, compile a list of images into an MPEG stream
* using the Stanford codec
*
* history
*
* 18/04/1994 fixed problems with odd sized pictures
*
* 16/04/1994 fixed a few bugs
*
* 13/04/1994 added requester that shows why the codec might have failed
* previously it just guessed memory problems
* turned redraw off for loading and preprocessing
*
* 03/03/1994 added checks to avoid frozen script when the codec never started
* (bad installation or memory problems)
*
* 28/01/1994 allows selection of a filter script to preprocess source frames
* also cosmetic changes
*
* 02/01/1994 tries to handle user abort
* should definitely work if aborted through 'waiting for activity'
* period.
*
* 01/01/1994 first version
*
* Copyright Michael van Elst 1994
*
* This program is freely distributable, but copyrighted by me. This means
* that you can copy it freely as long as you don't ask for any more money
* than a nominal fee for copying. This program may be put on PD disks,
* especially on Fred Fish's AmigaLibDisks.
* This program cannot be used for commercial purposes without permission
* from the author. The author can not be made responsible for any damage
* which is caused by using this program.
*
* This notice applies to the AREXX script, my changes to the MPEG codec
* done by the Portable Video Research Group at Stanford and the resulting
* executable contained in the BuildMPEG archive.
*/
OPTIONS RESULTS
/*logging='>"con:3/12/500/400/MPEG Log/AUTO/WAIT/CLOSE/INACTIVE"'*/
logging=''
profiling='sc:c/lprof -t5'
/*profiling=''*/
cleanup = nothing
SIGNAL ON BREAK_C
CALL ADDLIB("rexxsupport.library",0,-30,0)
CALL DoRequesters
CALL MakeOptions
CALL MainLoop
EXIT
/*-------------------------------------------------------------------------
*
* auxiliary functions
*
*-------------------------------------------------------------------------*/
/*
* check if argument is a positive integer
* if not then return default
*/
NumDefault:
procedure
parse arg input,low,high,default
if ~datatype(input,'w') | input<low | input>high
then return default
else return input
/*
* display an information requester with no special symbols in strings
*/
MyNotify:
procedure
parse arg prompt
string = ""
do until i=0
i = pos('%',prompt)
if i>0 then do
string = string || left(prompt,i) || '%'
prompt = substr(prompt,i+1)
end
else
string = string || prompt
end
requestnotify string
return
/*
* ensure reasonable defaults
*/
EnsureDefaults:
bitrate = numdefault(bitrate,0,100000,1200)
ffirst = numdefault(ffirst,0,999999,1)
flast = numdefault(flast,0,999999,10)
finterval = numdefault(finterval,0,99,3)
ginterval = numdefault(ginterval,0,99,2)
framerate = numdefault(framerate,1,8,3)
targetsize = numdefault(targetsize,0,10000000,0)
xingflag = numdefault(xingflag,0,1,0)
msdiameter = numdefault(msdiameter,1,15,15)
intramode = numdefault(intramode,0,1,0)
precisedct = numdefault(precisedct,0,1,0)
telescope = numdefault(telescope,0,1,1)
bounding = numdefault(bounding,0,1,0)
mvpredict = numdefault(mvpredict,0,1,0)
quantizer = numdefault(quantizer,0,31,0)
return
/*
* format a positive integer to have at least n digits
*/
MakeDigits:
procedure
arg v,n
l = length(v)
do while l<n
v = "0"v
l = l+1
end
return v
/*
* trim quotes from a string
*/
TrimQuotes:
procedure
parse arg in
l = length(in)
if l>1 & left(in,1)='"' & right(in,1)='"'
then out = substr(in,2,l-2)
else out = in
return out
/*-------------------------------------------------------------------------
*
* parameter requesters
*
*-------------------------------------------------------------------------*/
DoRequesters:
/*
* fetch last parameters
*/
inpattern = GETCLIP('MPEG_In')
ffirst = GETCLIP('MPEG_FirstFrame')
flast = GETCLIP('MPEG_LastFrame')
outfile = GETCLIP('MPEG_Out')
finterval = GETCLIP('MPEG_FInterval')
ginterval = GETCLIP('MPEG_GInterval')
framerate = GETCLIP('MPEG_Framerate')
bitrate = GETCLIP('MPEG_Bitrate')
targetsize = GETCLIP('MPEG_Targetsize')
xingflag = GETCLIP('MPEG_Xingflag')
cscript = GETCLIP('MPEG_Controlscript')
msdiameter = GETCLIP('MPEG_MSDiameter')
intramode = GETCLIP('MPEG_Intramode')
precisedct = GETCLIP('MPEG_PreciseDCT')
telescope = GETCLIP('MPEG_MVTelescoping')
bounding = GETCLIP('MPEG_DMVBounding')
mvpredict = GETCLIP('MPEG_MVPrediction')
quantizer = GETCLIP('MPEG_Quantization')
fscript = GETCLIP('MPEG_FilterScript')
CALL EnsureDefaults
fpsstring = '23.51fps 24fps 25fps 25.50fps 30fps 50fps 59.94fps 60fps'
if framerate>1 then
gadstring = subword(fpsstring,framerate,words(fpsstring)-framerate+1) || ,
" " || subword(fpsstring,1,framerate-1)
else
gadstring = fpsstring
gadstring = translate(gadstring,"/"," ")
Gadget.1 = 'S/125/20/Input Pattern:/'inpattern
Gadget.2 = 'I/330/20/From:/'ffirst
Gadget.3 = 'I/430/20/To:/'flast
Gadget.4 = 'S/125/35/Output Filename:/'outfile
Gadget.5 = 'I/125/50/Frame Interval:/'finterval
Gadget.6 = 'I/125/65/Group Interval:/'ginterval
Gadget.7 = 'C/430/35/Frame rate:/8/'gadstring
Gadget.8 = 'L/348/38/1/1/Frame rate:'
Gadget.9 = 'I/430/50/Bit rate:/'bitrate
Gadget.10 = 'I/430/65/Target size:/'targetsize
Gadget.11 = 'X/85/82/×ING Override/'xingflag
Gadget.12 = 'X/255/82/Query Advanced Options.../0'
Extras.1 = 'X/20/20/DC intraframe mode/'intramode
Extras.2 = 'X/20/35/Use Precise DCT/'precisedct
Extras.3 = 'S/130/80/Control Script:/'cscript
Extras.4 = 'X/280/20/Motion Vector Telescoping/'telescope
Extras.5 = 'X/280/35/Dynamic Motion Vector Bounding/'bounding
Extras.6 = 'X/280/50/Motion Vector prediction/'mvpredict
Extras.7 = 'I/420/65/Search diameter:/'msdiameter
Extras.8 = 'I/420/80/Quantization:/'quantizer
Extras.9 = 'S/130/65/IFX Filter:/'fscript
ComplexRequest '"MPEG Compiler"' 12 Gadget 540 120
IF rc ~= 0 then EXIT
/* fetch parameters back from requester */
inpattern = result.1
ffirst = result.2
flast = result.3
outfile = result.4
finterval = result.5
ginterval = result.6
fpsindex = result.7
bitrate = result.9
targetsize = result.10
xingflag = result.11
advanced = result.12
framerate = (fpsindex + (framerate-1)) // words(fpsstring) + 1
if advanced then do
ComplexRequest '"MPEG Advanced Options"' 9 Extras 540 120
if rc ~= 0 then EXIT
/* fetch parameters back from requester */
intramode = result.1
precisedct = result.2
cscript = result.3
telescope = result.4
bounding = result.5
mvpredict = result.6
msdiameter = result.7
quantizer = result.8
fscript = result.9
end
CALL EnsureDefaults
CALL SETCLIP('MPEG_In', inpattern)
CALL SETCLIP('MPEG_FirstFrame', ffirst)
CALL SETCLIP('MPEG_LastFrame', flast)
CALL SETCLIP('MPEG_Out', outfile)
CALL SETCLIP('MPEG_FInterval', finterval)
CALL SETCLIP('MPEG_GInterval', ginterval)
CALL SETCLIP('MPEG_Framerate', framerate)
CALL SETCLIP('MPEG_Bitrate', bitrate)
CALL SETCLIP('MPEG_Targetsize', targetsize)
CALL SETCLIP('MPEG_Xingflag', xingflag)
CALL SETCLIP('MPEG_Controlscript', cscript)
CALL SETCLIP('MPEG_MSDiameter', msdiameter)
CALL SETCLIP('MPEG_Intramode', intramode)
CALL SETCLIP('MPEG_PreciseDCT', precisedct)
CALL SETCLIP('MPEG_MVTelescoping', telescope)
CALL SETCLIP('MPEG_DMVBounding', bounding)
CALL SETCLIP('MPEG_MVPrediction', mvpredict)
CALL SETCLIP('MPEG_Quantization', quantizer)
CALL SETCLIP('MPEG_FilterScript', fscript)
/*
* split input pattern
*/
csep = pos(':',inpattern)
ssep = lastpos('/',inpattern)
if ssep>0 & ssep>csep then do
directory = left(inpattern,ssep)
infilename = substr(inpattern,ssep+1)
end
else if csep>0 & csep>ssep then do
directory = left(inpattern,csep)
infilename = substr(inpattern,csep+1)
end
else do
directory = ""
infilename = inpattern
end
csep = pos('%',infilename)
if csep>0 then do
ssep=csep+1
do while substr(infilename,ssep,1)='%'
ssep = ssep+1
end
inprefix = left(infilename,csep-1)
insuffix = substr(infilename,ssep)
indigits = ssep-csep
end
else do
inprefix = infilename
insuffix = ""
indigits = 1
end
return
/*-------------------------------------------------------------------------
*
* run a user command or script
*
*-------------------------------------------------------------------------*/
UserScript:
if pos(':',fscript)>0 then
filterfile = fscript
else
filterfile = "IMAGEFX:mpegfilters/"fscript
if open('filter',filterfile,'r') then do
rx quiet filterfile
call close('filter')
end
else if open('filter',filterfile'.ifx','r') then do
rx quiet filterfile".ifx"
call close('filter')
end
else
rxs fscript
return
/*-------------------------------------------------------------------------
*
* automatically preformat for XING files
*
*-------------------------------------------------------------------------*/
XingPreProc:
GetMain ; if result="" then EXIT
parse VAR result name width height depth .
if width ~= 160 | height ~= 120 then
scale 160 120
return
/*-------------------------------------------------------------------------
*
* create command line options for Stanford CODEC
*
*-------------------------------------------------------------------------*/
MakeOptions:
command = "IMAGEFX:mpeg/mpeg"
opts = "-PF" "-a" ffirst "-b" flast
check=statef(command)
parse var check typ len blocks perm .
if typ ~= "FILE" | substr(perm,7,1) ~= 'E' then do
call MyNotify("Sorry, can't find "command" or wrong permissions.")
EXIT
end
if xingflag then
opts = opts "-XING"
else do
if cscript ~= "" then do
if pos(':',cscript)>0 then
controlfile = cscript
else
controlfile = "IMAGEFX:mpegcontrol/"cscript
command = command '<"'controlfile'"'
opts = opts "-o"
end
if ~telescope then opts = opts "-NVNT"
if bounding then opts = opts "-DMVB"
if intramode then opts = opts "-4"
if mvpredict then opts = opts "-c"
if precisedct then opts = opts "-y"
if finterval>0 then opts = opts "-f" finterval
if ginterval>0 then opts = opts "-g" ginterval
if msdiameter>0 then opts = opts "-i" msdiameter
if bitrate>0 then opts = opts "-r" bitrate*1024
if framerate>0 then opts = opts "-p" framerate
if quantizer>0 then opts = opts "-q" quantizer
if targetsize>0 then opts = opts "-x" targetsize*8192
end
id = random(100,999,time('s'))
pipename = "PIPE:"address()"."id"="
portname = "IFX_BuildMPEGServer."id
statfile = 'T:CODE.return_status.'id
opts = opts "-REXX" portname||":"||mpeg
if outfile = "" then do
requestnotify "Sorry, you must given an output filename"
EXIT
end
/*
* preload first frame to determine size or
* to check size against XING values
*/
lastbuf = directory||inprefix||makedigits(ffirst,indigits)||insuffix
redraw off
loadbuffer lastbuf FORCE
if rc>0 then do
redraw on
requestnotify "Failed to preload first frame"
EXIT 10
end
CALL UserScript
if xingflag then CALL XingPreProc
redraw on
GetMain ; if result="" then EXIT
parse VAR result name width height depth .
/* round size up, YUVSPLIT does the same */
if (width // 2) > 0 then width = width + 1
if (height // 2) > 0 then height = height + 1
if xingflag then
do
if width ~= 160 | height ~= 120 then do
requestnotify "XING frames need to be of size 160x120 pixel"
EXIT
end
end
else
opts = opts "-h" width "-v" height
opts = opts "-s" '"'outfile'"' '"'pipename'"'
mpegcommand = command opts
return
/*-------------------------------------------------------------------------
*
* run the codec program and feed it with data
*
*-------------------------------------------------------------------------*/
MainLoop:
LockInput
Undo Off
cleanup = "restoreifx"
nullptr = '00000000'x
port = openport(portname);
if port = nullptr then do
call MyNotify("can't create server port '" portname "'")
exit
end
packet = "xx"
cleanup = "flushcodec"
CALL SETCLIP('MPEG_PipeName',"")
message "Running CODEC in the background"
pre = 'failat 99'
post1 = 'get RC >'statfile
post2 = 'rx "address '''portname''' x FAIL"'
sep = '+'x2c('0a')
address command "run" logging pre sep profiling mpegcommand sep post1 sep post2
if rc>0 then do
call MyNotify("can't create background process")
exit
end
framenumber = 1
do until subcommand = "FAIL"
cleanup = "flushcodec"
message "Waiting for activity on frame "framenumber
call waitpkt portname
do until packet=nullptr
packet = getpkt(portname);
if packet ~= nullptr then
do
command = getarg(packet,0)
call reply packet, 0 /* should be atomic */
packet = nullptr
parse var command prefix subcommand filespec x y .
CALL SETCLIP('MPEG_PipeName',filespec)
select
when subcommand = "LoadMem" then do
/* filespec is something like: PIPE:ident.random=framenr.Y */
csep = lastpos('=',filespec)
ssep = lastpos('.',filespec)
filetype = substr(filespec,ssep+1,1)
framenumber = substr(filespec,csep+1,ssep-csep-1)
framenumber = makedigits(framenumber,indigits)
message "pushing "filetype" data for frame "framenumber
newbuf = directory||inprefix||framenumber||insuffix
if lastbuf ~= newbuf then do
redraw off
loadbuffer newbuf FORCE
if rc>0 then do
requestnotify "Failed to read frame"||framenumber
SIGNAL BREAK_C
end
CALL UserScript
if xingflag then CALL XingPreProc
redraw on
lastbuf = newbuf
end
GetMain ; if result="" then SIGNAL BREAK_C
parse VAR result name width height depth .
/* round size up, YUVSPLIT does the same */
if (width // 2) > 0 then width = width + 1
if (height // 2) > 0 then height = height + 1
if filetype ~= 'Y' then do
width = width/2
height = height/2
end
/* this check fails when the framesize is not constant
* or a load failed (then width=height=0)
*/
if width ~= x | height ~= y then do
/* then we push an empty file which will
* make the codec abort
*/
filename = trimquotes(filespec)
call open('push',filename,'w')
call writeln('push',"STOP") /* some dummy data */
call close('push')
end
else
savebufferas YUVSPLIT filespec filetype
end
when subcommand = "EXIT" then
cleanup = "restoreifx"
when subcommand = "FAIL" then do
end
otherwise
call MyNotify("unknown command" subcommand)
end
end
end
end
code="Out of memory ?"
if open('result',statfile,'r') then do
code = readln('result')
call close('result')
select
when code=0 then code=0
when code=1 then code="Input values out of bounds."
when code=2 then code="Huffman decoder finds bad code."
when code=3 then code="Undefined value in encoder."
when code=4 then code="Error found in Marker."
when code=5 then code="Cannot initialize MPEG stream."
when code=6 then code="No recovery mode specified."
when code=7 then code="End of file unexpected."
when code=8 then code="Bad marker structure."
when code=9 then code="Cannot write output."
when code=10 then code="Cannot read input."
when code=11 then code="System parameter Error."
when code=12 then code="Memory allocation failure."
otherwise code="General failure."
end
end
if code~=0 then call MyNotify("MPEG encoder failed. "||code)
message "done"
call closeport(port);
address command "delete force file " statfile
UnlockInput
Undo On
return
/*-------------------------------------------------------------------------
*
* cleaning up
*
*-------------------------------------------------------------------------*/
BREAK_C:
/*
* beware.. we can't handle another break_c at this point
*/
select
when cleanup="restoreifx" then do
call closeport(port)
UnlockInput
Undo On
end
when cleanup="flushcodec" then do
call closeport(port) /* let all requests fail immediatly */
if (filespec ~= "") then do
filename = trimquotes(filespec)
if ~open('tryme',filename,'r') then do
if open('push',filename,'w') then do
call writeln('push',"STOP") /* some dummy data */
call close('push')
end
else
requestnotify "pushing data failed. Possible Hangup."
end
else do
call close('tryme')
end
end
UnlockInput
Undo On
end
otherwise
NOP
end
EXIT